<?php
/**
 * Fight - Classe de gestion des combats
 *
 * @author Staff Centaurius
 * @date 28 Dec 2007
 **/
class Fight {

	public $id_fight;
	public $fight_run;
	public $string_id;
	public $start_time;
	public $nb_rounds;
	public $sys_x;
	public $sys_y;
	private $flottes_teams;
	private $last_move;
	private $users;
	private $winner_team;

	/**
	* Constructeur d'objet
	**/
	public function __construct($id) {

		//Initialisation du combat
		$this->id_fight = $id;
		$this->string_id = $this->genFightId();
		$this->start_time = 0;
		$this->nb_rounds = 0;
		$this->sys_x = 0;
		$this->sys_y = 0;
		$this->flottes_teams = array();
		$this->flottes_teams[1] = array(); //flottes de l'équipe 1
		$this->flottes_teams[2] = array(); //flottes de l'équipe 2
		$this->users = array(); //joueurs du combat
		$this->winner_team = 0;

		//Chargement du combat
		$this->loadFight();

		//Activation du combat Ok
		$this->fight_run = true;
	}

	/**
	* Destructeur de l'objet combat
	* (appellé automatiquement a l'arret du démon ou a la destruction de l'objet)
	**/
	public function __destruct() {

		//Décharge le combat
		//$this->flottes_teams = NULL;
		//$this->users = NULL;

		return true;
	}

	/**
	* Chargement du combat
	* (et initialisation)
	**/
	public function loadFight() {

		$fight_create = true;

		$sql = "SELECT fgt_id, fgt_start_time FROM d_fight WHERE fgt_id = " . $this->id_fight . " LIMIT 1 ";
		$req = SQLManager::query($sql);
		$fight = SQLManager::fetch_array($req);

		if (isset($fight['fgt_id']) AND $fight['fgt_id'] = $this->id_fight) {

			//Timestamp du lancement du combat par les joueur
			$this->start_time = $fight['fgt_start_time'];

			//mise a jour de l'état du combat
			$sql_u = "UPDATE d_fight SET fgt_loaded = 1, fgt_string_id = '" . $this->string_id . "'
						WHERE fgt_id = " . $this->id_fight . " LIMIT 1 ";
			$fight_create = SQLManager::query($sql_u);
		}

		if ($fight_create == true) {
			//Combat chargé
			Log::logShell("Chargement du combat # " . $this->id_fight . " lance le " . date('d/m/Y H:i:s', $this->start_time), 4);
		} else {
			//Si mise a jour du combat nok
			Log::logShell("Impossible de charger le combat # " . $this->id_fight, 4);
			return false;
		}

		//chargement des flottes du combat
		$this->refreshFightFlotte();

		//Journalisation de l'image des flottes au début du combat
		$this->logRoundFlotte();

		unset($fight);

		return true;
	}

	/**
	* Rafraichissement des entrés / sorties de flottes
	**/
	public function refreshFightFlotte() {

		$flottes_arr = array();

		$sql = "SELECT ff.flt_id_ext, ff.fgt_team, ff.fgt_move, f.usr_id_ext, f.flt_nb_unt, us.usr_pseudo,
						f.flt_pts_vie, u.lang_unt_nom, u.unt_pts_vie, u.unt_pts_att, u.unt_pts_def, u.unt_class,
						u.unt_class_default, u.unt_nb_att, f.unt_id_ext, f.flt_sys_x, f.flt_sys_y, 0 as flt_damage
				FROM d_fight_flotte ff
				JOIN d_flotte f
					ON f.flt_id = ff.flt_id_ext
				JOIN s_unite u
					ON u.unt_id = f.unt_id_ext
				JOIN d_user us
					ON us.usr_id = f.usr_id_ext
				WHERE ff.fgt_id_ext = " . $this->id_fight . "
					AND ff.fgt_move <> ''";
		$req = SQLManager::query($sql);
		$flottes_arr = SQLManager::fetch_all($req, 'flt_id_ext');

		//Si aucune flottes trouvée
        if (count($flottes_arr) < 1) {
			return true;
        }

		foreach($flottes_arr as &$flotte) {

			if ($this->sys_x == 0 OR $this->sys_y == 0) {
				//Chargement de la position du combat
				$this->sys_x = $flotte['flt_sys_x'];
				$this->sys_y = $flotte['flt_sys_y'];
			}

			switch($flotte['fgt_move']) {
				case 'up':

					//Ajout de la flotte dans le combat
					$this->addFightFlotte($flotte, $flotte['fgt_team']);

					Log::logShell("Entre d'une flotte dans le combat", 1);
					break;

				case 'down':

					//Sortie de la flotte du combat
					$this->deleteFightFlotte($flotte['flt_id_ext']);

					Log::logShell("Sortie d'une flotte du combat", 1);
					break;
			}
		}

		unset($flottes_arr);

		//Vérification si le combat dois toujours tourner
		$this->updateFightStatus();
	}

	/**
	* Détermine si le combat dois continuer
	**/
	public function updateFightStatus() {

		//vars locale
		$nb_flt_team1 = count($this->flottes_teams[1]);
		$nb_flt_team2 = count($this->flottes_teams[2]);

		if ($nb_flt_team1 == 0 AND $nb_flt_team2 == 0) {

			//Les équipes sont ex-éco
			$this->winner_team = 3;

		} elseif ($nb_flt_team1 == 0 AND $nb_flt_team2 > 0) {

			//Victoire équipe 2
			$this->winner_team = 2;

		} elseif ($nb_flt_team2 == 0 AND $nb_flt_team1 > 0) {

			//Victoire équipe 1
			$this->winner_team = 1;
		}

		//Si il y a un vainceur (ou ex-eco)
		if ($this->winner_team != 0) {

			//Fin du combat
			$this->closeFight();

			return false;
		} else {

			//le combat continue
			return true;
		}
	}

	/**
	* Application des dégats du dernier tour sur les flottes du combat
	* - mise a jour des flottes
	* - sortie de celle détruites
	* - réinitialisation des valeur de tir
	**/
	public function updateFightFlotte() {

		//vars locales
		$new_life_pts = 0;
		$new_nb = 0;
		$flt_id = 0;

		//Pour chaque équipes
		foreach($this->flottes_teams as $tkey => &$teams) {

			//Pour chaque flotte de l'équipe
			foreach($teams as &$flotte) {

				$flt_id = $flotte['flt_id_ext'];
				//Si la flotte n'as pas été touché
				if (!isset($flotte['flt_damage']) OR $flotte['flt_damage'] == 0) {
					//Passage a la flotte suivante
					continue;
				}

				//Calcule des nouveaux point de vie
				$new_life_pts = $flotte['flt_pts_vie'] - $flotte['flt_damage'];
				//Calcule du nouveau nombre
				$new_nb = ceil($new_life_pts / $flotte['unt_pts_vie']);

				//Si plus de point de vie
				if ($new_life_pts <= 0) {

					//Arret de l'attaque d'astre (si elle attaque un astre)
					Flotte::cancelAttackAstre($flt_id);
					//Annulation de la colonisation (si colonisation
					Astre::cancelColoniseAstre($flt_id);

					//Sortie de la flotte du combat
					$this->deleteFightFlotte($flt_id);

					//destruction de la flotte
					Flotte::deleteFlotte($flt_id);

					//Passage a la flotte suivante
					continue;
				}

				//Mise a jour des valeurs de la flotte
				Flotte::updateFlotteValues($flt_id, $flotte['unt_id_ext'], $flotte['usr_id_ext'],
											$new_nb - $flotte['flt_nb_unt'], $new_life_pts - $flotte['flt_pts_vie']);

				//Mise a jour de la flotte
				$flotte['flt_pts_vie'] = $new_life_pts;
				$flotte['flt_nb_unt'] = $new_nb;
				//initialisation des valeur de tire
				$flotte['flt_damage'] = 0;
				$flotte['flt_select'] = 0;
				$flotte['flt_strike_val'] = 0;
			}
		}

		//Vérification si le combat dois toujours tourner
		$this->updateFightStatus();

		return true;
	}

	/**
	* Suppression d'une flotte du combat
	*
	* @param int $flotte_id
	* @param int $team (1 ou 2)
	**/
	private function deleteFightFlotte($flotte_id) {

		//Si la flotte existe en team 1
		if (isset($this->flottes_teams[1][$flotte_id])) {
			//Sortie de la flotte du combat
			unset($this->flottes_teams[1][$flotte_id]);
		}

		//Si la flotte existe en team 2
		if (isset($this->flottes_teams[2][$flotte_id])) {
			//Sortie de la flotte du combat
			unset($this->flottes_teams[2][$flotte_id]);
		}

		//Suppression de l'enregistrement jointure
		SQLManager::query("DELETE FROM d_fight_flotte WHERE flt_id_ext = $flotte_id LIMIT 1 ");
		//Mis a jour de l'état de la flotte
		SQLManager::query("UPDATE d_flotte SET flt_action = 0 WHERE flt_id = $flotte_id LIMIT 1 ");

		return true;
	}

	/**
	* Ajout d'une flotte dans le combat
	*
	* @param array $flotte_tbl
	* @param int $team (1 ou 2)
	**/
	private function addFightFlotte($flotte_tbl, $team) {

		//Si elle n'existe pas déja
		if (!isset($this->flottes_teams[$team][$flotte_tbl['flt_id_ext']])) {
			//Ajout de la flotte dans le combat
			$this->flottes_teams[$team][$flotte_tbl['flt_id_ext']] = $flotte_tbl;

			if (!isset($this->users[$flotte_tbl['usr_id_ext']])) {
				//Si le joueur n'es pas encore dans la liste
				$this->users[$flotte_tbl['usr_id_ext']] = array('pseudo' => $flotte_tbl['usr_pseudo'],
																'team' => $team);

				$subject = sprintf(_MAILFIGHTTITLE, $this->sys_x, $this->sys_y);
				$text = sprintf(_MAILENTERFIGHT, $this->string_id, $this->string_id);

				//Envois d'un MP au joueur qui entre dans le combat
				Mail::sendMail(SERVICE_USER, $flotte_tbl['usr_id_ext'], '[' . $flotte_tbl['usr_pseudo'] . ']', $subject, $text);
			}
		}

		//mise a jour de l'état du mouvement de la flotte dans le combat
		$sql_u = "UPDATE d_fight_flotte SET fgt_move = '' WHERE flt_id_ext = " . $flotte_tbl['flt_id_ext'] . " LIMIT 1 ";
		$req_u = SQLManager::query($sql_u);

		return true;
	}

	/**
	* Enregistre une image des flottes du tour
	**/
	public function logRoundFlotte() {

		//Encodage du tableau de flotte en JSON pour stockage
		$round_string = json_encode($this->flottes_teams);
		$now = time();

		//Enregistrement des flottes du round
		$sql = "INSERT INTO d_fight_rounds
				VALUE (" . $this->nb_rounds . ", " . $this->id_fight . ", '" . $round_string . "', '', " . $now . ")";

		$req = SQLManager::query($sql);

		unset($round_string);

		return $req;
	}

	/**
	* Genere un identifiant de combat
	**/
	private function genFightId() {

		$id_string = "";
		$char_arr = array_fill(0, 10, '');

		$gen_func = create_function('&$char', '$char = chr(mt_rand(97, 122)) . chr(mt_rand(48, 57));');
		array_walk($char_arr, $gen_func);
		$id_string = implode("", $char_arr);

		Log::logShell("Generation de l'identifiant de combat : " . $id_string, 3);
		return $id_string;
	}

	/**
	* Execution d'un tour de combat
	**/
	public function execFightRound() {

		$this->nb_rounds++;

		//Pour chaque flotte de l'équipe 1
		foreach($this->flottes_teams[1] as &$team1) {

			//initialisation du ciblage
			$team1['flt_select'] = 0;
			$team1['flt_strike_val'] = 0;
			$flotte_default = array();

			//récupération des flottes de la classe par défaut
			$flotte_default = $this->getFlottesClasse(trim($team1['unt_class_default']), 2);
			//si il y a des flottes de la classe par défaut
			if (count($flotte_default) > 0) {
				//Sélection d'une flotte ennemi dans la classe
				$team1['flt_select'] = array_rand($flotte_default);
			}

			if ($team1['flt_select'] == 0) {
				//Sinon sélection d'une flotte
				$team1['flt_select'] = array_rand($this->flottes_teams[2]);
			}

			if ($team1['flt_select'] == 0) {
				continue; //si aucune flotte ciblé, on passe a la suivante
			}

			//calcule des point de dégats par unité
			if ($team1['unt_pts_att'] < $this->flottes_teams[2][$team1['flt_select']]['unt_pts_vie']) {
				$team1['flt_strike_val'] = $team1['unt_pts_att'] * $team1['unt_nb_att'];
			} else {
				$team1['flt_strike_val'] = $this->flottes_teams[2][$team1['flt_select']]['unt_pts_vie'] * $team1['unt_nb_att'];
			}

			$this->flottes_teams[2][$team1['flt_select']]['flt_damage'] += $team1['flt_strike_val'] * $team1['flt_nb_unt'];
		}

		//Pour chaque flotte de l'équipe 2
		foreach($this->flottes_teams[2] as &$team2) {

			//initialisation du ciblage
			$team2['flt_select'] = 0;
			$team2['flt_strike_val'] = 0;
			$flotte_default = array();

			//récupération des flottes de la classe par défaut
			$flotte_default = $this->getFlottesClasse(trim($team2['unt_class_default']), 1);
			//si il y a des flottes de la classe par défaut
			if (count($flotte_default) > 0) {
				//Sélection d'une flotte ennemi dans la classe
				$team2['flt_select'] = array_rand($flotte_default);
			}

			if ($team2['flt_select'] == 0) {
				//Sinon sélection d'une flotte
				$team2['flt_select'] = array_rand($this->flottes_teams[1]);
			}

			if ($team2['flt_select'] == 0) {
				continue; //si aucune flotte ciblé, on passe a la suivante
			}

			//calcule des point de dégats par unité
			if ($team2['unt_pts_att'] < $this->flottes_teams[1][$team2['flt_select']]['unt_pts_vie']) {
				$team2['flt_strike_val'] = $team2['unt_pts_att'] * $team2['unt_nb_att'];
			} else {
				$team2['flt_strike_val'] = $this->flottes_teams[1][$team2['flt_select']]['unt_pts_vie'] * $team2['unt_nb_att'];
			}

			$this->flottes_teams[1][$team2['flt_select']]['flt_damage'] += $team2['flt_strike_val'] * $team2['flt_nb_unt'];
		}

		//Journalisation de l'image des flottes apres premier tour
		$this->logRoundFlotte();

		//Actualisation points de vie des flottes
		$this->updateFightFlotte();

		return true;
	}

	/**
	* Fais une sélection de flotte dans une équipe
	*
	* @param string $class_name (classe de vaisseau a sélectionner)
	* @param int $team (1 ou 2)
	* @return array flottes sélectionné (vide si aucune flotte de cette classe)
	**/
	private function getFlottesClasse($class_name, $team) {

		$flotte_selec = array();

		if (!isset($this->flottes_teams[$team]) OR count($this->flottes_teams[$team]) < 1) {
			//Si l'équipe demandé n'existe pas ou n'a plus de flotte
			return $flotte_selec;
		}

		//Pour chaque flottes de l'équipe
		foreach($this->flottes_teams[$team] as &$flottes) {

			//Si la flotte est de la classe demandé
			if (trim($flottes['unt_class']) == $class_name) {
				//Ajout de la flotte dans la selec
				$flotte_selec[$flottes['flt_id_ext']] = $flottes;
			}
		}

		return $flotte_selec;
	}

	/**
	* Termine le combat
	**/
	public function closeFight() {

		$now = time();

		//Pour chaque équipes
		foreach($this->flottes_teams as &$teams) {

			//Pour chaque flotte de l'équipe
			foreach($teams as &$flotte) {

				//Suppression de la flotte
				$this->deleteFightFlotte($flotte['flt_id_ext']);
			}
		}

		//mise a jour de l'enreg du combat
		$sql_u = "UPDATE d_fight SET fgt_end_time = $now, fgt_nb_round = " . $this->nb_rounds . ", fgt_winner_team = " . $this->winner_team . "
					WHERE fgt_id = " . $this->id_fight . " LIMIT 1 ";
		$req_u = SQLManager::query($sql_u);

		foreach($this->users as $k => $v) {

			if($v['team'] == $this->winner_team) {

				$text = sprintf(_MAILENDFIGHT, _WINNER, $this->string_id, $this->string_id);
			} else {
				$text = sprintf(_MAILENDFIGHT, _LOOSER, $this->string_id, $this->string_id);
			}
			//Envois d'un MP au joueur qui entre dans le combat
			Mail::sendMail(SERVICE_USER, $k, '[' . $v['pseudo'] . ']', _MAILENDFIGHTTITLE, $text);
		}

		//Desactivation du combat
		$this->fight_run = false;

		return true;
	}

}
?>